package org.origin.centre.support.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * Encrypt 工具
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
public final class EncryptUtil {
    private static final int KEY_SIZE = 128;
    private static final String AES_ALGORITHM = "AES";
    private static final String AES_MODE = "AES/CBC/PKCS5Padding";
    private static final String CHARSET_NAME = StandardCharsets.UTF_8.name();

    /**
     * AES加密字符串
     *
     * @param content  明文内容
     * @param password 加密密码
     * @return 加密结果
     */
    public static String encryptAes(String content, String password) {
        if (content == null || password == null) {
            throw new IllegalArgumentException("Content and password must not be null.");
        }

        try {
            byte[] secureRandomSeed = password.getBytes(CHARSET_NAME);
            SecretKey key = generateKey(secureRandomSeed);
            byte[] encrypted = encrypt(content.getBytes(CHARSET_NAME), key);

            return new String(Base64.getEncoder().encode(encrypted));
        } catch (Exception e) {
            // 使用日志框架记录异常，此处使用System.out.println()作为示例
            throw new IllegalArgumentException("AES加密失败", e);
        }
    }

    /**
     * 生成密钥
     *
     * @param secureRandomSeed 一个byte数组作为随机数种子，使用该种子生成一个SecureRandom对象
     * @return 生成并返回一个128位的密钥
     * @throws Exception 加密过程中的任何异常
     */
    private static SecretKey generateKey(byte[] secureRandomSeed) throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance(AES_ALGORITHM);
        SecureRandom secureRandom = new SecureRandom(secureRandomSeed);
        keyGen.init(128, secureRandom);
        return keyGen.generateKey();
    }

    /**
     * AES加密
     *
     * @param content 它接收一个内容字节数组
     * @param key     密钥
     * @return 返回经过AES加密后的内容字节数组
     * @throws Exception 加密过程中的任何异常
     */
    private static byte[] encrypt(byte[] content, SecretKey key) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(content);
    }

    /**
     * 解密AES加密过的字符串
     *
     * @param content  加密的内容
     * @param password 加密密码
     * @return 明文结果
     */
    public static String decryptAes(String content, String password) {
        try {
            byte[] raw = generateKey(password).getEncoded();
            SecretKey key = new SecretKeySpec(raw, AES_ALGORITHM);
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] byteContent = decoder.decode(content);
            byte[] byteDecode = cipher.doFinal(byteContent);
            return new String(byteDecode, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new IllegalArgumentException("AES解密失败", e);
        }
    }

    /**
     * 使用密码生成AES密钥
     *
     * @param password 密码
     * @return AES密钥
     * @throws Exception 如果密钥生成过程中遇到任何错误
     */
    private static SecretKey generateKey(String password) throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance(AES_ALGORITHM);
        SecureRandom secureRandom = new SecureRandom();
        // 这里可以添加盐值和密码强化机制，例如使用PBKDF2
        // 注意：这里将密码作为随机数源的种子，不是直接用于生成密钥，以提高随机性
        secureRandom.setSeed(password.getBytes(CHARSET_NAME));
        keyGen.init(128, secureRandom);
        return keyGen.generateKey();
    }

    /**
     * AES加密字符串
     *
     * @param content  明文内容
     * @param password 加密密码
     * @return 加密结果
     */
    public static String encryptAes2(String content, String password) {
        try {
            byte[] encryptedBytes = encrypt(content.getBytes(StandardCharsets.UTF_8), password);
            return encodeBytesToString(encryptedBytes);
        } catch (Exception e) {
            throw new IllegalArgumentException("AES2加密异常：", e);
        }
    }

    /**
     * 加密字节数组
     *
     * @param plainBytes 明文字节数组
     * @param password   加密密码
     * @return 加密后的字节数组
     * @throws Exception 加密过程中的任何异常
     */
    private static byte[] encrypt(byte[] plainBytes, String password) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(AES_ALGORITHM);
        kgen.init(KEY_SIZE);
        SecretKeySpec keySpec = new SecretKeySpec(password.getBytes(), AES_ALGORITHM);
        Cipher cipher = Cipher.getInstance(AES_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(plainBytes);
    }

    /**
     * 将字节数组编码为字符串
     *
     * @param bytes 待编码的字节数组
     * @return 编码后的字符串
     */
    private static String encodeBytesToString(byte[] bytes) {
        Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(bytes);
    }

    /**
     * 解密AES加密过的字符串
     *
     * @param content  加密的内容
     * @param password 加密密码
     * @return 明文结果
     * @throws IllegalArgumentException 如果输入参数为空或无效
     * @throws Exception                如果解密过程中遇到任何错误
     */
    public static String decryptAES(String content, String password) throws Exception {
        if (content == null || content.isEmpty() || password == null || password.isEmpty()) {
            throw new IllegalArgumentException("输入参数不能为空");
        }

        Base64.Decoder decoder = Base64.getDecoder();
        byte[] encryptBytes = decoder.decode(content);

        // 生成密钥
        SecretKey secretKey = generateKey(password);

        Cipher cipher = Cipher.getInstance(AES_MODE);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decryptBytes = cipher.doFinal(encryptBytes);

        return new String(decryptBytes);
    }

}
